package com.example.canal.event.listener;

import com.example.canal.common.bean.CanalBean;
import com.example.canal.common.constant.MysqlDBConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.Environment;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.Executor;


public abstract class AbstractDBChangeListener<T extends ApplicationEvent> implements ApplicationListener<T> {

    @Autowired
    private Environment env;

    protected void process(CanalBean canalBean,Executor executor) {
        String type = canalBean.getType();
        if (type == null) {
            return;
        }
        List<String> data = canalBean.getData();
        if (MysqlDBConstant.TYPE_INSERT.equals(type)) {
            execIfExecutor(executor,() -> onInsert(data));
        } else if (MysqlDBConstant.TYPE_DELETE.equals(type)) {
            execIfExecutor(executor,() -> onDelete(data));
        } else if (MysqlDBConstant.TYPE_UPDATE.equals(type)) {
            execIfExecutor(executor,() -> onUpdate(data,canalBean.getOld()));
        }

    }

    protected CanalBean preEvent(T t) {
        String listenerName = this.getClass().getName().replaceAll(".*\\.","");
        String disableKey = "dbchange.disable." + listenerName;
        String property = env.getProperty(disableKey);
        if ("true".equals(property)) {
            System.err.println(listenerName + " 监听已禁用！");
            return null;
        }

        CanalBean canalBean = Optional.ofNullable((CanalBean) t.getSource())
                .orElse(null);

        return canalBean;

    }

    public abstract void onInsert(List<String> data);

    public abstract void onDelete(List<String> data);

    public abstract void onUpdate(List<String> data,List<String> old);


    private void execIfExecutor(Executor executor,Runnable runnable) {
        if (executor == null) {
            runnable.run();
        } else {
            executor.execute(runnable);
        }
    }
}
